/*
 * File:   DataReferenceTerminal.h
 * Author: cpp
 *
 * Created on May 4, 2010, 3:49 AM
 */

#ifndef _DATAREFERENCETERMINAL_H

#define	_DATAREFERENCETERMINAL_H
#include "Terminal.h"
#include "SymbolDefinition.h"
#include "SQLStatement.h"
#include <map>

using namespace std;

class DataReferenceTerminal : public Terminal {
public:
    DataReferenceTerminal();
    DataReferenceTerminal(const DataReferenceTerminal& orig);
    virtual ~DataReferenceTerminal();
    void setPK(const string& k);
    void setId(const string& id);
    void setTable(const string& table);
    void setSymAttrib(const string& attrib);
    void setDefAttrib(const string& attrib);
    void addSymDef(SymbolDefinition sd);
    void buildFile(string path);
    string getSID();
    string getDSID();
    void buildSpec(string path);
    vector<string> getDML();
    void print();
    void printSymDef();

    const string& getTable() const {
        return table;
    }

    const string& getSymAttribute() const {
        return sym_attrib;
    }

    const string& getDefAttribute() const {
        return def_attrib;
    }

    const string& getPK() const {
        return PK;
    }
private:
    //
    string table;
    string sym_attrib;
    string def_attrib;
    //Value displayed by
    string sql_val;
    string PK;
    multimap<string, SymbolDefinition> reference;
    string getSpecId();

};

DataReferenceTerminal::DataReferenceTerminal() {
}

DataReferenceTerminal::DataReferenceTerminal(const DataReferenceTerminal& orig) {
    id = orig.id;
    table = orig.table;
    sym_attrib = orig.sym_attrib;
    def_attrib = orig.def_attrib;
    reference = orig.reference;
    value = orig.value;
    PK = orig.PK;
}

DataReferenceTerminal::~DataReferenceTerminal() {
}

void DataReferenceTerminal::setId(const string& id) {
    if ((id.substr(0, 3) == "(D:") && (id[id.size() - 1] == ')'))//and
    {
        this->id = id;
    } else {
        cerr << "DataReferenceTerminal ID must be of type (D:x)" << endl;
    }
}

void DataReferenceTerminal::setTable(const string& tbl) {
    this->table = tbl;
}

void DataReferenceTerminal::setPK(const string& k) {
    this->PK = k;
}

void DataReferenceTerminal::setDefAttrib(const string& attrib) {
    this->def_attrib = attrib;
}

void DataReferenceTerminal::setSymAttrib(const string& attrib) {
    this->sym_attrib = attrib;
}

void DataReferenceTerminal::addSymDef(const SymbolDefinition sd) {
    string dkey;

    dkey = sd.getMask();

    if (dkey == "") {
        dkey = sd.getSymbol();
    }

    reference.insert(pair<string, SymbolDefinition > (dkey, sd));

}

void DataReferenceTerminal::buildFile(string filename) {

    ofstream myfile(filename.c_str(), ios::app);
    myfile << ".DRT" << "\n";
    myfile << "ID: " << this->getId() << "\n";
    myfile << "TN: " << this->getTable() << "\n"; //tablename
    myfile << "PK: " << this->getPK() << "\n";
    myfile << "SA: " << this->getSymAttribute() << "\n";
    myfile << "DA: " << this->getDefAttribute() << "\n";
    multimap<string, SymbolDefinition>::iterator it;
    for (it = reference.begin(); it != reference.end();
            ++it) {
        SymbolDefinition& d = (*it).second;

        myfile << d.getSymbol() << "\t" << d.getDefinition();
        myfile << "\t" << d.getMask() << "\n";
    }
    myfile << ".END_DRT" << "\n\n";
    myfile.close();
}


//Get the DRT id for accent specification file

string DataReferenceTerminal::getSID() {
    //TO-DO: StringStream
    string head;
    string sid;
    head = "DRT";
    sid = this->getId();

    sid = sid.substr(3, sid.size() - 4);

    head.append(sid.append(" "));
    return head;
}

string DataReferenceTerminal::getDSID() {
    //TO-DO: StringStream
    string SID;
    SID = this->getSID();
    string::iterator sit;
    sit = SID.end() - 2; //TODO: why -2
    if ((*sit) == '!') {
        SID.erase(sit);
    }
    return SID;
}

void DataReferenceTerminal::buildSpec(string filename) {

    string r, m;
    string SID;

    SID = this->getSID();
    cout << "EXPAND: " << SID << endl;
    ofstream specfile(filename.c_str(), ios::app);
    specfile << SID << ":\n";
    multimap<string, SymbolDefinition>::iterator it;

    for (it = reference.begin(); it != reference.end();
            ++it) {
        SymbolDefinition& d = (*it).second;
        if (it != reference.begin()) {
            specfile << "| ";
        }
        r = d.getSymbol();
        if (d.getMask() == "") {

            string::iterator itr;

            for (itr = r.begin(); itr != r.end(); ++itr)
                specfile << "'" << *itr << "' ";
            specfile << "{ println(\"" << this->getId() << " = " << r;
            specfile << "\");\n";
            specfile << "setLastVal(\"" << r << "\");\n";
            specfile << "setLastDRT(\"" << this->getId() << "\");\n";

            specfile << "}\n";


        } else {
            m = d.getMask();
            string::iterator itr;
            for (itr = m.begin(); itr != m.end(); ++itr)
                specfile << "'" << *itr << "'";
            specfile << "{ println(\"" << this->getId() << " = " << r;
            specfile << "\");} ";
        }

    }

    specfile << ";" << "\n";
    specfile.close();
}

//Populating the table (for local use) using DRT content
//Returns a vector of strings, ofwhich the strings are actually sql statements.
//to use when building the local database from MAP file
vector<string> DataReferenceTerminal::getDML(){
    vector<string> SQL;
    stringstream sqlss,sqlres;
    string sqlhead;
    string sqltail;
    sqlss << "INSERT INTO " << table << "(" << sym_attrib << "," << def_attrib;
    sqlss <<  ") VALUES (";
    sqlhead = sqlss.str();
    sqltail = ");";


    multimap<string, SymbolDefinition>::iterator it;
    for (it = reference.begin(); it != reference.end();
            ++it) {
        SymbolDefinition& d = (*it).second;
        sqlss.str("");
        sqlres.str("");
        sqlss << d.getSymbol() << "," << d.getDefinition();
        //cout << sqlss.str() << endl;
        sqlres << sqlhead << sqlss.str() << sqltail;
        //string result = sqlres.str();
        cout << "Adding to DBS file: " << endl;
        cout << sqlres.str() << endl;
        SQL.push_back(sqlres.str());
    }

    return SQL;
}


void DataReferenceTerminal::printSymDef() {

    multimap<string, SymbolDefinition>::iterator it;
    int i = 1;
    for (it = reference.begin(); it != reference.end();
            ++it) {
        SymbolDefinition& d = (*it).second;

        cout << i << ".\t" << d.getSymbol() << "\t" << d.getDefinition();
        cout << "\t" << d.getMask() << "\n";
        i++;
    }
}


#endif	/* _DATAREFERENCETERMINAL_H */